package container.map;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author: 李德才
 * @description:
 * @create: 2020-12-13 18:22
 **/
public class Test_ConcurrentHashMap {

    /**
     * https://xie.infoq.cn/article/901e4fa89353a6dfb63490c3d
     */

    /**
     * ConcurrentHashMap 支持高并发，添加效率低，获取效率高
     * <p>
     * 如果没有初始化就先调用initTable（）方法来进行初始化过程
     * 如果没有hash冲突就直接CAS插入,如果插入失败则进入自旋转（for 死循环 ），直到成功
     * 如果还在进行扩容操作就先进行扩容
     * 如果存在hash冲突，即槽点有值，就加锁（synchronized）让其与线程不能操作来保证线程安全，
     * 这里有两种情况，一种是链表形式就直接遍历到尾端插入，一种是红黑树就按照红黑树结构插入，
     * 最后一个如果Hash冲突时会形成Node链表，在链表长度超过8，Node数组超过64时会将链表结构转换为红黑树的结构
     * 如果添加成功就调用addCount（）方法统计size，并且检查是否需要扩容
     */

    /**
     * 总结：
     * 快的原因是没有完全使用线程锁，而是使用自旋锁和CAS操作
     * 安全的原因是因为当发现槽点有值，启动锁机制保证当前只有一个线程可以将值存入指定槽点
     */
    static Map<UUID, UUID> m = new ConcurrentHashMap<>();

    static int count = Constants.COUNT;
    static UUID[] keys = new UUID[count];
    static UUID[] values = new UUID[count];
    static final int THREAD_COUNT = Constants.THREAD_COUNT;

    static {
        for (int i = 0; i < count; i++) {
            keys[i] = UUID.randomUUID();
            values[i] = UUID.randomUUID();
        }
    }

    static class MyThread extends Thread {
        int start;
        int gap = count / THREAD_COUNT;

        public MyThread(int start) {
            this.start = start;
        }

        @Override
        public void run() {
            for (int i = start; i < start + gap; i++) {
                m.put(keys[i], values[i]);
            }
        }
    }

    public static void main(String[] args) {

        long start = System.currentTimeMillis();

        Thread[] threads = new Thread[THREAD_COUNT];

        for (int i = 0; i < threads.length; i++) {
            threads[i] =
                    new MyThread(i * (count / THREAD_COUNT));
        }

        for (Thread t : threads) {
            t.start();
        }

        for (Thread t : threads) {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        long end = System.currentTimeMillis();
        System.out.println(end - start);

        System.out.println(m.size());

        //-----------------------------------

//        start = System.currentTimeMillis();
//        for (int i = 0; i < threads.length; i++) {
//            threads[i] = new Thread(() -> {
//                for (int j = 0; j < 10000000; j++) {
//                    m.get(keys[10]);
//                }
//            });
//        }
//
//        for (Thread t : threads) {
//            t.start();
//        }
//
//        for (Thread t : threads) {
//            try {
//                t.join();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
//
//        end = System.currentTimeMillis();
//        System.out.println(end - start);
    }

}
